package com.xyy.saas.payment.query.core.trade.impl;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.TransactionResultBO;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.enums.TransactionStatusEnum;
import com.xyy.saas.payment.cores.enums.TransactionTypeEnum;
import com.xyy.saas.payment.cores.param.TransactionParam;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.dao.mapper.RefundOrderMapper;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.PrePayOrder;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.payment.core.service.PrePayOrderService;
import com.xyy.saas.payment.query.core.trade.AbstractTransactionQuery;
import com.xyy.saas.payment.service.PayResultOrderService;
import com.xyy.saas.payment.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Slf4j
public class TransactionRefundQuery extends AbstractTransactionQuery {

    @Autowired
    private PrePayOrderService prePayOrderService;
    @Resource
    private RefundOrderMapper refundOrderMapper;
    @Resource
    private PayResultOrderService payResultOrderService;
    @Autowired
    private RouteManager routeManager;

    @Override
    protected ResultVO checkParam(TransactionParam param) {
        if(null == param) {
            return ResultVO.create(ResultCodeEnum.PARAM_ERROR);
        }
        if(StringUtils.isBlank(param.getTradeNo())) {
            return ResultVO.create(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        if(StringUtils.isBlank(param.getChannel())) {
            return ResultVO.createError("渠道不能为空");
        }
        return ResultVO.createSuccess();
    }

    @Override
    protected TransactionResultBO queryLocalRecord(TransactionParam param) throws PaymentException {
        RefundOrder refundOrder = refundOrderMapper.selectByRefundNo(param.getTradeNo());
        if(null == refundOrder) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(refundOrder.getPayNo(), param.getChannel());
        if(payResultOrder == null) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        if(RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) {
            return TransactionResultBO.build(refundOrder.getRefundNo(), TransactionStatusEnum.SUCCESS.getCode(), refundOrder.getAmount(), refundOrder.getChannel(), DateUtil.dateToLong(refundOrder.getSuccessTime()), refundOrder.getChannelChargeNo(), refundOrder.getBusinessRefundNo(), payResultOrder.getMerchantId());
        }
        if(RefundOrder.STATUS_FAIL.equals(refundOrder.getStatus())) {
            return TransactionResultBO.build(refundOrder.getRefundNo(), TransactionStatusEnum.FAIL.getCode(), refundOrder.getAmount(), refundOrder.getChannel(), DateUtil.dateToLong(refundOrder.getSuccessTime()), refundOrder.getChannelChargeNo(), refundOrder.getBusinessRefundNo(), payResultOrder.getMerchantId());
        }
        return TransactionResultBO.build(param.getTradeNo(), TransactionStatusEnum.TRANSACTING.getCode());
    }

    @Override
    protected boolean checkIfQueryChannel(TransactionResultBO resultBO) {
        if(TransactionStatusEnum.SUCCESS.getCode().equals(resultBO.getStatus())
                || TransactionStatusEnum.FAIL.getCode().equals(resultBO.getStatus())) {
            return false;
        }
        return true;
    }

    @Override
    protected TransactionResultBO queryChannelRecord(TransactionParam param) throws PaymentException {
        RefundOrder refundOrder = refundOrderMapper.selectByRefundNo(param.getTradeNo());

        if(null == refundOrder) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }

        PrePayOrder prePayOrder = prePayOrderService.getPrePayOrderByPayNo(refundOrder.getPayNo());
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(refundOrder.getPayNo(), param.getChannel());

        if(null == payResultOrder || null == prePayOrder) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }

        param.setBusinessOrderType(prePayOrder.getBusinessOrderType());
        param.setPayMode(payResultOrder.getPayMode());
        return routeManager.getAdapter(payResultOrder.getPayChannel(), StringUtils.EMPTY, prePayOrder.getReceiverId()).queryTransaction(param);
    }

    @Override
    protected void processChannelRecord(TransactionParam param, TransactionResultBO channelRecord) throws PaymentException{
        RefundOrder refundOrder = refundOrderMapper.selectByRefundNo(param.getTradeNo());
        channelRecord.setBusinessOrderNo(refundOrder.getBusinessRefundNo());
        // 状态改变，更新数据库
        if (TransactionStatusEnum.SUCCESS.getCode().equals(channelRecord.getStatus()) && !RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) {
            int count = refundOrderMapper.updateStatusByRefundNo(param.getTradeNo(), refundOrder.getChannelRefundNo(), refundOrder.getSuccessTime(), refundOrder.getUpdateTime(), RefundOrder.STATUS_FINISH, refundOrder.getChannelTransactionNo(), refundOrder.getVersion());
            if(count < 1) {
                log.error("QueryTradeService#queryPay update sql error refundOrder:{}", JSON.toJSONString(refundOrder));
                throw new PaymentException(ResultCodeEnum.DATABASE_ERROR);
            }
        }
        if (TransactionStatusEnum.FAIL.getCode().equals(channelRecord.getStatus()) && !RefundOrder.STATUS_FAIL.equals(refundOrder.getStatus())) {
            int count = refundOrderMapper.updateStatusByRefundNo(param.getTradeNo(), refundOrder.getChannelRefundNo(), refundOrder.getSuccessTime(), refundOrder.getUpdateTime(), RefundOrder.STATUS_FAIL, refundOrder.getChannelTransactionNo(), refundOrder.getVersion());
            if(count < 1) {
                log.error("QueryTradeService#queryPay update sql error refundOrder:{}", JSON.toJSONString(refundOrder));
                throw new PaymentException(ResultCodeEnum.DATABASE_ERROR);
            }
        }
    }

    @Override
    public TransactionTypeEnum getTransactionType() {
        return TransactionTypeEnum.REFUND;
    }
}
